{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "3ebbee14",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using the Community license in this session. If you have a full Xpress license, first set the XPAUTH_PATH environment variable to the full path to your license file, xpauth.xpr, and then restart Python. If you want to use the FICO Community license and no longer want to see this message, set the XPAUTH_PATH environment variable to: /home/maged/anaconda3/envs/balance/lib/python3.8/site-packages/xpress/license/community-xpauth.xpr\n",
      "NB: setting XPAUTH_PATH will also affect any other Xpress products installed on your system.\n"
     ]
    }
   ],
   "source": [
    "# Importing modules\n",
    "try:\n",
    "    import hsbalance as hs;\n",
    "except ImportError:\n",
    "    !pip install hsbalance\n",
    "    import hsbalance as hs;"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1045eff9",
   "metadata": {},
   "source": [
    "# Introduction\n",
    "\n",
    "This notebook discuss how the `hsbalance` package handles ill-conditioned planes problem"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d840eef",
   "metadata": {},
   "source": [
    "Darlow discussed in his paper `Darlow, M. S. \"The identification and elimination of non-independent balance planes in influence coefficient balancing.\" Turbo Expo: Power for Land, Sea, and Air. Vol. 79603. American Society of Mechanical Engineers, 1982.` three test cases can be found in test cases in `/test/`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a602bc7e",
   "metadata": {},
   "source": [
    "## Parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f8088da8",
   "metadata": {},
   "outputs": [],
   "source": [
    "ALPHA_math=[\n",
    "                            ['1.41@45', '3.61@34', '3.61@34'],\n",
    "                            ['3.16@72', '2.24@27', '2.24@27'],\n",
    "                            ['2.83@45', '5@37', '5@37'],\n",
    "                            ['3.16@18', '3.61@34', '4.47@27']]\n",
    "A_math=[\n",
    "                            ['3.16@72'], \n",
    "                            ['3.16@18'],\n",
    "                            ['4.12@14'],\n",
    "                            ['5.39@68']]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7144ede",
   "metadata": {},
   "source": [
    "Convert to complex numbers (cartesian) form"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7933f461",
   "metadata": {},
   "outputs": [],
   "source": [
    "A = hs.convert_matrix_to_cart(A_math)\n",
    "ALPHA = hs.convert_matrix_to_cart(ALPHA_math)\n",
    "# A, ALPHA"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9524b2c9",
   "metadata": {},
   "source": [
    "Adding ALPHA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "eb13e858",
   "metadata": {},
   "outputs": [],
   "source": [
    "alpha = hs.Alpha()\n",
    "alpha.add(direct_matrix=ALPHA)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "a41c59f0",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "Not a square matrix --> no exact solution.\n",
      "\n",
      "Ill-conditioned found in plane # [1]\n"
     ]
    }
   ],
   "source": [
    "alpha.check()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eaf33269",
   "metadata": {},
   "source": [
    "A warning is raised that plane[1] (the second plane, remember python starts counting from 0) is ill-conditioned.  \n",
    "Ill-conditioned planes mean that they are algebraically depending on other planes. It means the ill-conditioned plane carries not new information to the system. When solving(especially with least squares method) the system tend to infiltrate (adding excessive masses at these planes)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "a3f92b25",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Influence Coefficient Matrix\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Coefficient Values\n",
      "==============================\n",
      "              Plane 1      Plane 2      Plane 3\n",
      "Sensor 1  1.41 @ 45.0  3.61 @ 34.0  3.61 @ 34.0\n",
      "Sensor 2  3.16 @ 72.0  2.24 @ 27.0  2.24 @ 27.0\n",
      "Sensor 3  2.83 @ 45.0   5.0 @ 37.0   5.0 @ 37.0\n",
      "Sensor 4  3.16 @ 18.0  3.61 @ 34.0  4.47 @ 27.0\n",
      "==============================\n",
      "End of Coefficient Values\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n"
     ]
    }
   ],
   "source": [
    "print(alpha)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c81228e",
   "metadata": {},
   "source": [
    "## Solving with Least squares:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "6b55e039",
   "metadata": {},
   "outputs": [],
   "source": [
    "model_LeastSquares = hs.LeastSquares(A, alpha, name='Least_squares') # Instantiate least square model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "25d4e6ab",
   "metadata": {},
   "outputs": [],
   "source": [
    "W_LeastSquares = model_LeastSquares.solve() #solve"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "918ed0cd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['0.875 @ 99.4'],\n",
       "       ['4.777 @ 98.0'],\n",
       "       ['5.137 @ 271.1']], dtype='<U13')"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hs.convert_matrix_to_math(W_LeastSquares)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "73f67625",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['1.638 @ 124.2'],\n",
       "       ['0.46 @ 180.4'],\n",
       "       ['1.288 @ 315.4'],\n",
       "       ['0.0 @ 238.0']], dtype='<U13')"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "residuals_LeastSquares = model_LeastSquares.expected_residual_vibration()\n",
    "hs.convert_matrix_to_math(residuals_LeastSquares) # Expected residule vibrations"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6360299c",
   "metadata": {},
   "source": [
    "Root mean square error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "132aa695",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.8464"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rmse_LeastSquares = model_LeastSquares.rmse()\n",
    "rmse_LeastSquares"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "03102a20",
   "metadata": {},
   "source": [
    "### Discussion\n",
    "The second plane is ill-conditioned as seen from the check, caused the second and third planes to increase the masses excessively."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "2c0f3846",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "Not a square matrix --> no exact solution.\n",
      "\n",
      "Ill-conditioned found in plane # [1]\n",
      "\n",
      "Removing Ill-conditioned plane # [1]\n",
      "\n",
      "IC matrix before removing\n",
      "[['1.41 @ 45.0' '3.61 @ 34.0' '3.61 @ 34.0']\n",
      " ['3.16 @ 72.0' '2.24 @ 27.0' '2.24 @ 27.0']\n",
      " ['2.83 @ 45.0' '5.0 @ 37.0' '5.0 @ 37.0']\n",
      " ['3.16 @ 18.0' '3.61 @ 34.0' '4.47 @ 27.0']]\n",
      "\n",
      "\n",
      "IC matrix after removing\n",
      "[['1.41 @ 45.0' '3.61 @ 34.0']\n",
      " ['3.16 @ 72.0' '2.24 @ 27.0']\n",
      " ['2.83 @ 45.0' '5.0 @ 37.0']\n",
      " ['3.16 @ 18.0' '4.47 @ 27.0']]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "alpha.check(ill_condition_remove=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84155239",
   "metadata": {},
   "source": [
    "by turning ill_condition_remove boolean to True we remove the second plane (ill-conditioned)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "29bef081",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Influence Coefficient Matrix\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Coefficient Values\n",
      "==============================\n",
      "              Plane 1      Plane 2\n",
      "Sensor 1  1.41 @ 45.0  3.61 @ 34.0\n",
      "Sensor 2  3.16 @ 72.0  2.24 @ 27.0\n",
      "Sensor 3  2.83 @ 45.0   5.0 @ 37.0\n",
      "Sensor 4  3.16 @ 18.0  4.47 @ 27.0\n",
      "==============================\n",
      "End of Coefficient Values\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n"
     ]
    }
   ],
   "source": [
    "print(alpha)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa4e2d8f",
   "metadata": {},
   "source": [
    "## Solving with Least squares:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "86c7e564",
   "metadata": {},
   "outputs": [],
   "source": [
    "model_LeastSquares = hs.LeastSquares(A, alpha, name='Least_squares') # Instantiate least square model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "eae81519",
   "metadata": {},
   "outputs": [],
   "source": [
    "W_LeastSquares = model_LeastSquares.solve() #solve"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "6c7def4f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['0.524 @ 44.4'],\n",
       "       ['1.137 @ 204.5']], dtype='<U13')"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hs.convert_matrix_to_math(W_LeastSquares)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12671ab8",
   "metadata": {},
   "source": [
    "Remember those are weights for first and third planes as plane 2 has been removed by check."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "876cf14e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['1.186 @ 168.2'],\n",
       "       ['0.826 @ 34.3'],\n",
       "       ['2.835 @ 297.3'],\n",
       "       ['2.514 @ 98.7']], dtype='<U13')"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "residuals_LeastSquares = model_LeastSquares.expected_residual_vibration()\n",
    "hs.convert_matrix_to_math(residuals_LeastSquares) # Expected residule vibrations"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e4b23d2",
   "metadata": {},
   "source": [
    "Root mean square error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "d2fd9071",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.8401"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rmse_LeastSquares = model_LeastSquares.rmse()\n",
    "rmse_LeastSquares"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "91b63eb3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL TYPE\n",
      "==================================================\n",
      "LeastSquares\n",
      "==================================================\n",
      "End of MODEL TYPE\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL NAME\n",
      "==================================================\n",
      "Least_squares\n",
      "==================================================\n",
      "End of MODEL NAME\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "INFLUENCE COEFFICIENT MATRIX\n",
      "==================================================\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Influence Coefficient Matrix\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Coefficient Values\n",
      "==============================\n",
      "              Plane 1      Plane 2\n",
      "Sensor 1  1.41 @ 45.0  3.61 @ 34.0\n",
      "Sensor 2  3.16 @ 72.0  2.24 @ 27.0\n",
      "Sensor 3  2.83 @ 45.0   5.0 @ 37.0\n",
      "Sensor 4  3.16 @ 18.0  4.47 @ 27.0\n",
      "==============================\n",
      "End of Coefficient Values\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "==================================================\n",
      "End of INFLUENCE COEFFICIENT MATRIX\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "INITIAL VIBRATION\n",
      "==================================================\n",
      "            Vibration\n",
      "Sensor 1  3.16 @ 72.0\n",
      "Sensor 2  3.16 @ 18.0\n",
      "Sensor 3  4.12 @ 14.0\n",
      "Sensor 4  5.39 @ 68.0\n",
      "==================================================\n",
      "End of INITIAL VIBRATION\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "SOLUTION\n",
      "==================================================\n",
      "        Correction Masses\n",
      "Plane 1      0.524 @ 44.4\n",
      "Plane 2     1.137 @ 204.5\n",
      "==================================================\n",
      "End of SOLUTION\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "RMSE\n",
      "==================================================\n",
      "1.8401\n",
      "==================================================\n",
      "End of RMSE\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "Resiudal Vibration Expected\n",
      "==================================================\n",
      "         Expected Vibration\n",
      "Sensor 1      1.186 @ 168.2\n",
      "Sensor 2       0.826 @ 34.3\n",
      "Sensor 3      2.835 @ 297.3\n",
      "Sensor 4       2.514 @ 98.7\n",
      "==================================================\n",
      "End of Resiudal Vibration Expected\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n"
     ]
    }
   ],
   "source": [
    "print(model_LeastSquares.info())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc67cae5",
   "metadata": {},
   "source": [
    "### Discussion\n",
    "by removing the second the correction weights at plane 3 has reduced to less than 4 times (from 5.14 kg to 1.14 kg). This causes a rise of RMSE and residual vibration on the other hand.   \n",
    "It is left to the engineer judgment weather to remove (or constrain) the ill-conditioned planes or leave it to get the best RMSE possible.  \n",
    "The target of this package is to give the engineer the best possible consulting service."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "255ee9dd",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:balance] *",
   "language": "python",
   "name": "conda-env-balance-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
